package com.hanxiaozhang.threadbase1ndedition.no10threadpool;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 功能描述: <br>
 * 〈工作窃取线程池，底层是ForkJoinPool〉
 * <p>
 * 假设共有三个线程同时执行, A, B, C
 * 当A,B线程池尚未处理任务结束,而C已经处理完毕,则C线程会从A或者B中窃取任务执行,这就叫工作窃取。
 * 假如：A线程中的队列里面分配了5个任务，而B线程的队列中分配了1个任务，当B线程执行完任务后，
 * 它会主动的去A线程中窃取其他的任务进行执行。
 *
 *
 * @Author:hanxinghua
 * @Date: 2021/11/25
 */
public class No12WorkStealingPool {


    /*
      工作窃取(WorkStealing)算法：
      ## 概念：
      指某个线程从其他队列里窃取任务来执行。
      ## 简单介绍：
      把大任务分割为若干个互不依赖的子任务，为了减少线程间的竞争，把这些子任务分别放到不同的队列里，
      并为每个队列创建一个单独的线程来执行队列里的任务，线程和队列一一对应。比如：线程1负责处理1队列里的任务，
      2线程负责2队列的。但是，所有的线程会先把自己队列里的任务干完，然后在帮助其他队列干活。
      ## 优点：
      充分利用线程进行并行计算，减少线程间的竞争。
      ## 缺点：
      在某些情况下还是会存在竞争，比如双端队列里只有一个任务时。并且该算法会消耗更多的系统资源，
      比如创建多个线程和多个双端队列。
     */


    public static void main(String[] args) throws IOException {

        System.out.println("集群的CPU核数："+Runtime.getRuntime().availableProcessors());
        // workStealingPool 会自动启动cpu核数个线程去执行任务
        ExecutorService service = Executors.newWorkStealingPool();


        service.execute(new Task(1000));
        service.execute(new Task(1000));
        for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) {
            service.execute(new Task(5000));
        }

        // 阻塞
        System.in.read();
    }

    static class Task implements Runnable {

        private int time;

        Task(int t) {
            this.time = t;
        }

        @Override
        public void run() {
            try {
                TimeUnit.MILLISECONDS.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(time + " " + Thread.currentThread().getName());
        }

    }
}
